package com.qijian.plug.capacity.approval;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.qijian.common.annotation.Log;
import com.qijian.common.core.domain.entity.FlowableApproval;
import com.qijian.common.enums.ApprovalDescriptionEnum;
import com.qijian.common.enums.BusinessType;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.DateUtils;
import com.qijian.common.utils.mybatis.WhereEntityTool;
import com.qijian.flowable.domain.FlowableForm;
import com.qijian.flowable.domain.FlowableRecord;
import com.qijian.flowable.domain.query.FlowableRecordQuery;
import com.qijian.flowable.domain.vo.ProcessInstanceVo;
import com.qijian.flowable.service.IFlowableFormService;
import com.qijian.flowable.service.IFlowableRecordService;
import com.qijian.flowable.service.IProcessInstanceService;
import com.qijian.tool.domain.Msg;
import com.qijian.tool.service.IMsgService;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author qijian
 */
@Component
@RequiredArgsConstructor
public class ApprovalProcess extends ApprovalPlugWrapper<FlowableApproval.Approval> {

    private final IProcessInstanceService processInstanceService;
    private final RepositoryService repositoryService;
    private final IFlowableFormService flowableFormService;
    private final IFlowableRecordService flowableRecordService;
    private final IMsgService msgService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doSomething(List<Object> args) {
        this.operation(args);
    }

    @Log(title = "流程发起", businessType = BusinessType.APPROVAL)
    protected void operation(List<Object> args) {
        // ID
        Long id = (Long) args.get(0);
        // 流程Key
        String processDefinitionKey = args.get(1).toString();
        Map<String, Object> values = new HashMap<>(3);
        // 流程
        ApprovalDescriptionEnum status = null;
        // 用户
        Long userId = ObjectUtil.isNotNull(args.get(2)) ? Long.valueOf(args.get(2).toString()) : null;
        // 部门
        Long deptId = ObjectUtil.isNotNull(args.get(3)) ? Long.valueOf(args.get(3).toString()) : null;
        // 用户名称
        String nickName = ObjectUtil.isNotNull(args.get(4)) ? args.get(4).toString() : null;
        String title = nickName;
        String content = "";
        String url = null;
        String title1 = "";
        String title2 = "";
        values.put("userId", userId);
        values.put("deptId", deptId);
        values.put("nickName", title);
        values.put("userName", nickName);
        values.put("createTime", DateUtils.getCurrentStrDate(DatePattern.NORM_DATETIME_PATTERN));
        if (args.size() > 5) {
            values.put("deptName", ObjectUtil.isNotNull(args.get(5)) ? args.get(5).toString() : null);
        }

        if (status == null) {
            throw new ServiceException("E01:单据信息错误！");
        }

        FlowableRecordQuery recordQuery = new FlowableRecordQuery();
        recordQuery.setBusinessKey(processDefinitionKey);
        recordQuery.setSourceId(id);
        FlowableRecord flowableRecord = flowableRecordService.getOne(WhereEntityTool.invoke(recordQuery));
        status = flowableRecord == null ? ApprovalDescriptionEnum.A : status;
        if (flowableRecord != null && status.getValue().equals(flowableRecord.getStatus())) {
            throw new ServiceException("E01:单据状态错误！");
        } else if (status == ApprovalDescriptionEnum.B) {
            throw new ServiceException("E01:单据审核中！");
        } else if (status == ApprovalDescriptionEnum.C) {
            throw new ServiceException("E01:单据已审核！");
        }
        // 查询流程
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        processDefinitionQuery.processDefinitionKey(processDefinitionKey).latestVersion();
        ProcessDefinition definition = processDefinitionQuery.singleResult();
        if (ObjectUtil.isNotNull(definition)) {
            // 流程表单
            FlowableForm flowableForm = flowableFormService.getById(processDefinitionKey);
            JSONArray jsonField = JSONUtil.parseObj(flowableForm.getFormJson()).getJSONArray("list");
            String idField = null;
            for (int i = 0; i < jsonField.size(); i++) {
                if ("ID".equals(jsonField.getJSONObject(i).getStr("name"))) {
                    idField = jsonField.getJSONObject(i).getStr("model");
                    break;
                }
            }

            if (idField == null) {
                throw new ServiceException("E01:流程表单错误！");
            }

            // 流程数据
            ProcessInstanceVo instanceVo = new ProcessInstanceVo();
            instanceVo.setProcessDefinitionId(definition.getId());
            values.put("isFunction", false);
            values.put(idField, args.get(0).toString());
            values.put("approvalData", DateUtils.getDate());
            values.put("processInstanceFormData", JSONUtil.toJsonStr(values));
            values.put("createId", userId);
            instanceVo.setValues(values);
            instanceVo.setSourceId(id);
            // 发起流程
            Map<String, Object> result = processInstanceService.start(instanceVo);
            String processInstanceId = (String) result.get("processInstanceId");
            String processTitle = (String) result.get("title");
            List<Msg> msgs = new ArrayList<>(16);
            if (result.get("parent") != null) {
                Msg msg = new Msg();
                msg.setSourceId(processInstanceId);
                msg.setSourceType(processDefinitionKey);
                msg.setUserId((Long) result.get("parent"));
                msg.setTitle(processTitle);
                msg.setCreateBy(nickName);
                msg.setContent(content);
                msg.setUrl(url);
                msgs.add(msg);
            }
            if (result.get("users") != null) {
                List<String> userList = (List<String>) result.get("users");
                for (String u : userList) {
                    Msg msg = new Msg();
                    msg.setSourceId(processInstanceId);
                    msg.setSourceType(processDefinitionKey);
                    msg.setUserId(Long.valueOf(u));
                    msg.setTitle(processTitle);
                    msg.setCreateBy(nickName);
                    msg.setContent(content);
                    msg.setUrl(url);
                    msgs.add(msg);
                }
            }
            if (result.get("groups") != null) {
                List<String> groupList = (List<String>) result.get("groups");
            }

            if (CollectionUtil.isNotEmpty(msgs)) {
                msgService.saveBatch(msgs);
            }
        }
    }
}
